-
Notifications
You must be signed in to change notification settings - Fork 69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IF: Create new efficient incremental Merkle tree #2361
Conversation
For 10 levels of recursion, we used ~1540 bytes of stack. This translates to 5KB of stack space (32 levels of recursion) for appending 4 billion digests (the max. possible number of blocks). Since the default Ubuntu stack for a process is 10MB, and 2MB for a thread, this means that, even for a thread, we'd use at most 5/2000, or 0.25% of the stack available for any append(). If the stack is already 99.75% used before `incremental_merkle_tree::append()` is called, we have a problem elsewhere.
…acy` and simplify `unittests/merkle_tree_tests.cpp`
…what `mask` means.
return hash_combine(start[0], start[1]); | ||
else { | ||
if (async && size >= 4096) { // below 4096, starting async threads is overkill | ||
std::array<std::future<digest_type>, 4> fut; // size dictates the number of threads (must be power of two) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is likely fine as it is only 4 threads. We do need to be mindful of thread usage as we don't want to overwhelm a system so that it slows down the main thread. Other thread usage is setup at startup. Would be nice to be able to provide an io_context
for these tasks so they could run on the chain thread pool; however likely not worth the effort.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated it so that it uses only 2 threads up to 4096 digests, and 4 for 4096 and up.
libraries/chain/include/eosio/chain/incremental_merkle_legacy.hpp
Outdated
Show resolved
Hide resolved
Note:start |
Resolves #2333
This PR provides a new Merkle tree implementation which does not unnecessarily store extra digests and does not do extra hashes.
Previous versions are renamed:
incremental_merkle_tree_legacy
,calculate_merkle_legacy
.New versions are named:
incremental_merkle_tree
,calculate_merkle
.Note: Even though the files have been renamed
incremental_merkle_legacy.hpp
andmerkle_legacy.hpp
, the implementation has not been modified (besides remoning thecanonical
template parameter).New
incremental_merkle_tree
calculate_merkle
)append()
.incremental_merkle_tree_legacy
.uint64_t
and avector<digest_type>
whose size() isstd::popcount(num_digest_appended)
.New
calculate_merkle
incremental_merkle_tree
).calculate_merkle_legacy
without multithreadingsize() > 4096
, in which case it is 2x to almost 4x faster (2x for sequences of at least 10k digests, 4x for very large sequences).deque<digest_type>
.New performance tests
This PR adds two performance tests comparing the
legacy
andnew
merkle tree implementations./unittests/unit_test "--run_test=merkle_tree_tests/perf_test_one_large"
./unittests/unit_test "--run_test=merkle_tree_tests/perf_test_many_small"
New consistency test
This PR adds a test checking consistency between
incremental_merkle_tree
andcalculate_merkle
when adding from 1 to 1000 digests:./unittests/unit_test "--run_test=merkle_tree_tests/consistency_over_large_range"